/*
 * Copyright 2019-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.qp.basics.common.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @author:
 * @date: 2020/6/11 16:28
 * @apiNote: JDK 8  新日期类 格式化与字符串转换 工具类
 */
public class DateUtil {

    public static final DateTimeFormatter DFY_MD_HMS = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    public static final DateTimeFormatter DFY_MD = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

    /**
     * LocalDateTime 转时间戳
     *
     * @param localDateTime /
     * @return /
     */
    public static Long getTimeStamp(LocalDateTime localDateTime) {
        return localDateTime.atZone(ZoneId.systemDefault()).toEpochSecond();
    }

    /**
     * 时间戳转LocalDateTime
     *
     * @param timeStamp /
     * @return /
     */
    public static LocalDateTime fromTimeStamp(Long timeStamp) {
        return LocalDateTime.ofEpochSecond(timeStamp, 0, OffsetDateTime.now().getOffset());
    }

    /**
     * LocalDateTime 转 Date
     * Jdk8 后 不推荐使用 {@link Date} Date
     *
     * @param localDateTime /
     * @return /
     */
    public static Date toDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * LocalDate 转 Date
     * Jdk8 后 不推荐使用 {@link Date} Date
     *
     * @param localDate /
     * @return /
     */
    public static Date toDate(LocalDate localDate) {
        return toDate(localDate.atTime(LocalTime.now(ZoneId.systemDefault())));
    }


    /**
     * Date转 LocalDateTime
     * Jdk8 后 不推荐使用 {@link Date} Date
     *
     * @param date /
     * @return /
     */
    public static LocalDateTime toLocalDateTime(Date date) {
        return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
    }

    /**
     * 日期 格式化
     *
     * @param localDateTime /
     * @param patten /
     * @return /
     */
    public static String localDateTimeFormat(LocalDateTime localDateTime, String patten) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern(patten);
        return df.format(localDateTime);
    }

    /**
     * 日期 格式化
     *
     * @param localDateTime /
     * @param df /
     * @return /
     */
    public static String localDateTimeFormat(LocalDateTime localDateTime, DateTimeFormatter df) {
        return df.format(localDateTime);
    }

    /**
     * 日期格式化 yyyy-MM-dd HH:mm:ss
     *
     * @param localDateTime /
     * @return /
     */
    public static String localDateTimeFormatyMdHms(LocalDateTime localDateTime) {
        return DFY_MD_HMS.format(localDateTime);
    }

    /**
     * 日期格式化 yyyy-MM-dd
     *
     * @param localDateTime /
     * @return /
     */
    public String localDateTimeFormatyMd(LocalDateTime localDateTime) {
        return DFY_MD.format(localDateTime);
    }

    /**
     * 字符串转 LocalDateTime ，字符串格式 yyyy-MM-dd
     *
     * @param localDateTime /
     * @return /
     */
    public static LocalDateTime parseLocalDateTimeFormat(String localDateTime, String pattern) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
        return LocalDateTime.from(dateTimeFormatter.parse(localDateTime));
    }

    /**
     * 字符串转 LocalDateTime ，字符串格式 yyyy-MM-dd
     *
     * @param localDateTime /
     * @return /
     */
    public static LocalDateTime parseLocalDateTimeFormat(String localDateTime, DateTimeFormatter dateTimeFormatter) {
        return LocalDateTime.from(dateTimeFormatter.parse(localDateTime));
    }

    /**
     * 字符串转 LocalDateTime ，字符串格式 yyyy-MM-dd HH:mm:ss
     *
     * @param localDateTime /
     * @return /
     */
    public static LocalDateTime parseLocalDateTimeFormatyMdHms(String localDateTime) {
        return LocalDateTime.from(DFY_MD_HMS.parse(localDateTime));
    }

    /**
     * 用途：以指定的格式格式化日期字符串
     * @param pattern 字符串的格式
     * @param currentDate 被格式化日期
     * @return String 已格式化的日期字符串
     * @throws NullPointerException 如果参数为空
     */
    public static String formatDate(Date currentDate, String pattern){
        if(currentDate == null || "".equals(pattern) || pattern == null){
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(currentDate);
    }

    /**
     * 时间格式转换成string
     * @return
     */
    public static String DateToString() {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        String dateString = formatter.format(new Date());
        return dateString;
    }

    /**
     * 获取当前日期的下一天日期
     * @return
     */
    public static String nextDateString() {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cdate = Calendar.getInstance();
        cdate.setTime(new Date());
        cdate.add(Calendar.DAY_OF_MONTH, 1);
        String dateString = formatter.format(cdate.getTime());
        return dateString;
    }

    /**
     * 获取当前日期的上一天日期
     * @return
     */
    public static String prevDateString() {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cdate = Calendar.getInstance();
        cdate.setTime(new Date());
        cdate.add(Calendar.DAY_OF_MONTH, -1);
        String dateString = formatter.format(cdate.getTime());
        return dateString;
    }

    /**
     * 指定日期格式转换成string
     * @param currentTime
     * @return
     */
    public static String DateToString(Date currentTime) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        String dateString = formatter.format(currentTime);
        return dateString;
    }

    /**
     * 当前日期时间格式转换成string
     * @return
     */
    public static String DateTimeToString() {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = formatter.format(new Date());
        return dateString;
    }

    /**
     *当前时间格式转换成string
     * @return
     */
    public static String TimeToString() {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = formatter.format(new Date());
        return dateString.split(" ")[1];
    }

    /**
     * 指定日期时间格式转换成string
     * @param currentTime
     * @return
     */
    public static String DateTimeToString(Date currentTime) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = formatter.format(currentTime);
        return dateString;
    }

    /**
     * string格式转换成时间
     * @param str
     * @return
     */
    public static Date StringToDate(String str) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = null;
        try {
            date = formatter.parse(str);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }

    /**
     * string时间格式转换成string时间格式
     * @param dateTime
     * @return
     */
    public static String StringToDateTimeStr(String dateTime) {
        String[] aa = dateTime.split(" ");
        String aa1 = aa[0];
        String aa2 = aa[1];
        String[] front = aa1.split("-");
        String[] back = aa2.split(":");
        String year = front[0];
        String month = (front[1].length() < 2 ? ("0" + front[1]) : front[1]);
        String day = (front[2].length() < 2 ? ("0" + front[2]) : front[2]);
        String hour = (back[0].length() < 2 ? ("0" + back[0]) : back[0]);
        String min = (back[1].length() < 2 ? ("0" + back[1]) : back[1]);
        String ss = (back[2].length() < 2 ? ("0" + back[2]) : back[2]);
        return (year + "-" + month + "-" + day + " " + hour + ":" + min + ":" + ss);
    }

    /**
     * //获取当前日期的最后一天
     * @param date yyyy-MM
     * @return
     */
    public static String getMonthLastDay(String date){
        String [] dates=date.split("-");
        int year=Integer.parseInt(dates[0]);
        int month=Integer.parseInt(dates[1]);
        Calendar cal = Calendar.getInstance();
        //设置年份
        cal.set(Calendar.YEAR,year);
        //设置月份
        cal.set(Calendar.MONTH, month-1);
        //获取某月最大天数
        int lastDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
        //设置日历中月份的最大天数
        cal.set(Calendar.DAY_OF_MONTH, lastDay);
        //格式化日期
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String lastDayOfMonth = sdf.format(cal.getTime());

        return lastDayOfMonth;
    }

    /**
     * 获取某季度的第一天和最后一天
     *	@param num 第几季度
     */
    public static String[] getCurrQuarter(int year,int num) {
        String[] s = new String[2];
        String str = "";
        // 设置本年的季
        Calendar quarterCalendar = null;
        switch (num) {
            case 1: // 本年到现在经过了一个季度，在加上前4个季度
                quarterCalendar = Calendar.getInstance();
                quarterCalendar.set(Calendar.YEAR,year);
                quarterCalendar.set(Calendar.MONTH, 3);
                quarterCalendar.set(Calendar.DATE, 1);
                quarterCalendar.add(Calendar.DATE, -1);
                str = DateUtil.formatDate(quarterCalendar.getTime(), "yyyy-MM-dd");
                s[0] = str.substring(0, str.length() - 5) + "01-01";
                s[1] = str;
                break;
            case 2: // 本年到现在经过了二个季度，在加上前三个季度
                quarterCalendar = Calendar.getInstance();
                quarterCalendar.set(Calendar.YEAR,year);
                quarterCalendar.set(Calendar.MONTH, 6);
                quarterCalendar.set(Calendar.DATE, 1);
                quarterCalendar.add(Calendar.DATE, -1);
                str = DateUtil.formatDate(quarterCalendar.getTime(), "yyyy-MM-dd");
                s[0] = str.substring(0, str.length() - 5) + "04-01";
                s[1] = str;
                break;
            case 3:// 本年到现在经过了三个季度，在加上前二个季度
                quarterCalendar = Calendar.getInstance();
                quarterCalendar.set(Calendar.YEAR,year);
                quarterCalendar.set(Calendar.MONTH, 9);
                quarterCalendar.set(Calendar.DATE, 1);
                quarterCalendar.add(Calendar.DATE, -1);
                str = DateUtil.formatDate(quarterCalendar.getTime(), "yyyy-MM-dd");
                s[0] = str.substring(0, str.length() - 5) + "07-01";
                s[1] = str;
                break;
            case 4:// 本年到现在经过了四个季度，在加上前一个季度
                quarterCalendar = Calendar.getInstance();
                quarterCalendar.set(Calendar.YEAR,year);
                str = DateUtil.formatDate(quarterCalendar.getTime(), "yyyy-MM-dd");
                s[0] = str.substring(0, str.length() - 5) + "10-01";
                s[1] = str.substring(0, str.length() - 5) + "12-31";
                break;
        }
        return s;
    }


    public static long getDateDays(String startDate,String endDate){
        long betweenDate=0;
        try {
            //开始时间
            Date sDate  = sdf.parse(startDate);
            //结束时间
            Date eDate = sdf.parse(endDate);
            //得到相差的天数 betweenDate
            betweenDate = (eDate.getTime() - sDate.getTime())/(60*60*24*1000);

        } catch (ParseException e) {
            e.printStackTrace();
        }
        return betweenDate;
    }

    // 使用当前月份,得到上一个月的月份:月份的格式是:yyyy-MM
    public static String getLastDate(String currentDate) {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
            date = sdf.parse(currentDate + "-" + "01");
        } catch (ParseException e) {
            e.printStackTrace();
        }

        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.MONTH, -1);

        String month=String.valueOf(c.get(Calendar.MONTH)+ 1);
        if((c.get(Calendar.MONTH)+ 1)<10){
            month="0"+(c.get(Calendar.MONTH)+ 1);
        }
        String lastDate = c.get(Calendar.YEAR) + "-"
                + month;

        return lastDate;

    }

    /**
     * 根据开始时间和指定天数得到当前周期的开始日期  （用于n天做一次排行）
     * @param startTime 开始时间
     * @param pollCycle 周期天数
     * @return
     */
    public static String getpollCycleStartDate(String startTime,Long pollCycle) {
        //获取当前时间
        String dangqian=sdf.format(new Date());
        Date d1= null;
        try {
            d1 = sdf.parse(startTime);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        Date d2= null;
        try {
            d2 = sdf.parse(dangqian);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        // 获取当前时间减去活动开始时间差个多少天
        long daysBetween=(d2.getTime()-d1.getTime()+1000000)/(60*60*24*1000);
        System.out.println("相隔 "+daysBetween+" 天");
        //相隔天数除以五天 获取周期数
        long periodicnumbers=daysBetween/pollCycle;
        System.out.println("周期数:"+periodicnumbers);
        //把周期数强制类型转换为int然后乘5
        int cheng= (int) (pollCycle*(periodicnumbers));

        Calendar rightNow = Calendar.getInstance();
        rightNow.setTime(d1);
        //日期加指定天数 例如：rightNow.add(Calendar.DAY_OF_YEAR,10);2021-01-10+10天
        rightNow.add(Calendar.DAY_OF_YEAR,cheng);
        Date dt1=rightNow.getTime();
        //最终获取活动开始时间+5*1日期
        String reStr = sdf.format(dt1);
        System.out.println("时间:"+reStr);

        return reStr;
    }

    /**
     * @description 获取指定时间段的每周最后一天时间集合
     * @param beginTime 开始时间
     * @param endTime 结束时间
     * @return java.util.List
     * @throws Exception
     */
    public static List<String> getEveryWorkLastDayList(String beginTime, String endTime) throws Exception{
        Calendar c_begin = new GregorianCalendar();
        Calendar c_end = new GregorianCalendar();
        Date beginDate = sdf.parse(beginTime);
        Date endDate = sdf.parse(endTime);

        Calendar calendar1 = new GregorianCalendar();
        calendar1.setTime(beginDate);
        int year = calendar1.get(Calendar.YEAR);
        int month1 = calendar1.get(Calendar.MONTH);
        int day_of_month1 = calendar1.get(Calendar.DAY_OF_MONTH);

        Calendar calendar2 = new GregorianCalendar();
        calendar2.setTime(endDate);
        int month2 = calendar2.get(Calendar.MONTH);
        int day_of_month2 = calendar2.get(Calendar.DAY_OF_MONTH);


        c_begin.set(year, month1, day_of_month1); //Calendar的月从0-11，所以4月是3.
        c_end.set(year, month2, day_of_month2); //Calendar的月从0-11，所以5月是4.
        c_end.add(Calendar.DAY_OF_YEAR, 1);  //结束日期下滚一天是为了包含最后一天
        List<String> list=new ArrayList<>();
        int i=0;
        while(c_begin.before(c_end)){
            i++;
            if(i%7==0) {
                String firstAndLastOfWeek = getFirstAndLastOfWeek(sdf.format(c_begin.getTime()));
                list.add(firstAndLastOfWeek);
            }
            c_begin.add(Calendar.DAY_OF_YEAR, 1);
        }

        String lastTime = list.get(list.size() - 1).split("~")[1];
        if(sdf.parse(lastTime).getTime()<c_end.getTimeInMillis()){
            Date lastDate = sdf.parse(lastTime);
            Calendar calendar = new GregorianCalendar();
            calendar.setTime(lastDate);
            calendar.add(calendar.DATE,1);//把日期往后增加一天.整数往后推,负数往前移动
            String lateStr = sdf.format(calendar.getTime());
            list.add(lateStr+"~"+sdf.format(endDate.getTime()));
        }
        System.out.println(JSON.toJSONString(list));
        return list;
    }

    /**
     * @description 获取当前时间的这周开始和结束时间字符串
     * @param date 当前时间
     * @return java.util.String
     * @throws ParseException
     */
    public static String getFirstAndLastOfWeek(String date) throws ParseException {
        Date InputDate = sdf.parse(date);
        Calendar cDate = Calendar.getInstance();
        cDate.setFirstDayOfWeek(Calendar.MONDAY);
        cDate.setTime(InputDate);

        Calendar firstDate = Calendar.getInstance();

        firstDate.setFirstDayOfWeek(Calendar.MONDAY);
        firstDate.setTime(InputDate);

        Calendar lastDate = Calendar.getInstance();
        lastDate.setFirstDayOfWeek(Calendar.MONDAY);
        lastDate.setTime(InputDate);

        if (cDate.get(Calendar.WEEK_OF_YEAR) == 1 && cDate.get(Calendar.MONTH) == 11) {
            firstDate.set(Calendar.YEAR, cDate.get(Calendar.YEAR) + 1);
            lastDate.set(Calendar.YEAR, cDate.get(Calendar.YEAR) + 1);
        }

        int typeNum = cDate.get(Calendar.WEEK_OF_YEAR);
        firstDate.set(Calendar.WEEK_OF_YEAR, typeNum);
        firstDate.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        // 所在周开始日期
        String beginDate = sdf.format(firstDate.getTime());
        lastDate.set(Calendar.WEEK_OF_YEAR, typeNum);
        lastDate.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
        // 所在周结束日期
        String endDate = sdf.format(lastDate.getTime());
        return beginDate+ "~" + endDate ;
    }

    /**
     * 获取当前日期与此日期之间相隔多少天
     * @return
     */
    public static int getDays(String BegTime) throws ParseException {
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Date date1 = format.parse(BegTime);
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(date1);
        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(new Date());
        int day1= cal1.get(Calendar.DAY_OF_YEAR);
        int day2 = cal2.get(Calendar.DAY_OF_YEAR);

        int year1 = cal1.get(Calendar.YEAR);
        int year2 = cal2.get(Calendar.YEAR);
        if(year1 != year2) //同一年
        {
            int timeDistance = 0 ;
            for(int i = year1 ; i < year2 ; i ++)
            {
                if(i%4==0 && i%100!=0 || i%400==0) //闰年
                {
                    timeDistance += 366;
                }
                else //不是闰年
                {
                    timeDistance += 365;
                }
            }
            return timeDistance + (day2-day1) ;
        }
        else //不同年
        {
            return day2-day1;
        }
    }

    /**
     * 获取当前日期是星期几<br>
     *
     * @param datetime
     * @return 当前日期是星期几
     */
    public static JSONObject getWeekOfDate(String datetime) {
        Date dt = new Date();
        if(datetime!=null){
            dt = StringToDate(datetime);
        }
        String[] weekDays = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
        Calendar cal = Calendar.getInstance();
        cal.setTime(dt);
        int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (w < 0)
            w = 0;
        JSONObject json = new JSONObject();
        json.put("weekDay",weekDays[w]);// 当前是周几
        json.put("monthWeekNum",cal.get(Calendar.WEEK_OF_MONTH));// 当前是当月的第几周
        json.put("yearWeekNum",cal.get(Calendar.WEEK_OF_YEAR));// 当前是当年的第几周
        return json;
    }

    public static void main(String[] args) {
        //System.out.println(TimeToString());
        System.out.println(getWeekOfDate(null));
    }
}
